iT邦幫忙

2022 iThome 鐵人賽

DAY 26
1
Web 3

Road Map To DApp Developer系列 第 26

【DAY26】Verification System (Verify On Front-end)

  • 分享至 

  • xImage
  •  

Preface

昨天將資料在使用者端加鹽過後,今天要將這筆資料做驗證,但是要如何驗證是一個讓我想破頭的事,由於 keccak256 的 hash 方式是一個非對稱式加密,我們在系統中要如何再取得用戶資訊並同時進行驗證,這一點讓我想了很久。

Fetch QrData

上次我們使用了 component-qrscanner 這個套件來得到 QRCode 的資訊,現在我們也會利用這個套件來完成驗證所需要做到的事情。

const fn = (e) => {
    if(e.text) {
      const QrData = e.text;
      
    }
    else {
      alert('error: ' +  e.error);
    }
  }
  const scanner = new CreateQRScanner(fn);
  scanner.start()
  return ( 
    <div></div>
  );

上次使用的程式碼長這樣,其實我之前一直搞不懂在 react 中的 event 到底代表什麼,因此今日我也想趁機來搞懂他的意思。

What is event

Prototype JS

原生的 js 中會使用「addEventListener」負責「偵測發生了什麼事」,例如在我的(學校)作業中有遇到要將自己刻的一個 Google Meet 網頁上的人物踢出,可以看下圖:

在這段區塊中的我使用很多層 tag 來包起來,最後我使用下面這段程式來讓電腦偵測到我點擊了 cancel 的按鍵。

let cancelBtns = document.querySelectorAll('#cancelBtn');

Array.from(cancelBtns).forEach(function(cancelBtn){
    cancelBtn.addEventListener('click', function(e) {
        const audBox = e.target.parentElement.parentElement.parentElement;    
        audBox.parentNode.removeChild(audBox);
        accountNum -= 1;
        if (accountNum === 1) {
            mainChar.style.width = '100%';
            audiences.style.width = '0%';
        }
    });
});

簡單說就是我們利用 document.querySelectorAll(id) 來抓到全部具有 #cancelBtn 這個 id 的tag (回傳一個 list),再使用 Array.from().forEach() 來遍歷整個 list,這時當我們按下按鈕時就會被 cancelBtn.addEventListener(‘click’, function) 監測到並開始執行其中的函式。

React JS

在 React.js 中使用了 W3C 在 2016 改動的 UI Events,這個 UI Event 便是用來處理 Client 端使用滑鼠或鍵盤時與前端的互動媒介。


event 在 DOM 中的傳遞流程

通常我們使用的都是 event listener,其主要是提供一個 EventListener 的介面,並會提供一個 callback function: handleEvent()。而 Eventhandler() 會觸發 event.target 這個 Object,前段便可以使用這個 Object 執行收到 event 後的 statement。

在 React 中可以直接呼叫 event,而不用像原生 JS 使用 addEventListener(),方便了很多。

onClick = e => {...}

Get Back to QrScanner

了解了 event 在做什麼後,回過頭看那段程式應該是可以輕鬆了解。

const fn = (e) => {}

首先函式一開始傳入一個 event,可以用這個函式來得知使用者的任何操作,
在此是指 webCam 的掃描動作。

當 event 接收到任何資料的時候會回傳一個 object:

format: 11
numBits: 528
rawBytes: Uint8Array(66) [64, 83, 7, 134, 99, 54, 97, 1, 189, 41, 209, 5, 88, 153, 142, 25, 24, 204, 217, 24, 77, 204, 13, 153, 77, 205, 88, 204, 204, 140, 24, 204, 88, 196, 7, 213, 9, 217, 64, 246, 22, 22, 70, 35, 99, 70, 51, 150, 22, 54, 35, 86, 67, 118, 65, 2, 69, 93, 50, 103, 64, 54, 67, 51, 0, 236, buffer: ArrayBuffer(66), byteLength: 66, byteOffset: 0, length: 66, Symbol(Symbol.toStringTag): 'Uint8Array']
resultMetadata: Map(2) {2 => Array(4), 3 => 'H'}
resultPoints: (4) [e, e, e, e]
text: "0xf3f978628bf8dc3da706e75c320c1c8521579aadb64c9acb5d7d085844615d30"
timestamp: 1665377085645
[[Prototype]]: Object

我們需要的則是裡面的 e.text,因此用一個變數qrData 將他抓起來。


這邊用 wikipedia 的 QRCode,測試成功!(好害羞)

What's next?

由於我們在 Client 端已經使用 keccak256() 進行雜湊了,因此我們能做的驗證方式就是一樣 fetch Opensea 上的資料,然後將 ticket Owner 的 address 一個個做同樣的 hash,將其轉換成一個 array,若是有 hash 在裡面表示「這個使用者確實是使用我們的前端加密轉換成 QRCode 的!

這邊的做法可能會在使用者數量很大的時候出現問題,感覺應該可以使用後端先儲存,並在收到 QRCode 資料的時候去後端驗證。但是因為我目前無法處理後端的開發,未來可能會改善。

Implement

那就事不宜遲直接來實作吧!

首先使用 useEffect() 來偵測是否有 fetch 到資料,有的話再確認是否已將 ownership 處理過並丟到 hashedOwnerList 中。

useEffect(() => {
    if (nftData !== null) {
      if (hashedOwnerList.length !== nftData.top_ownerships.length){
        // first generate ownership array
        const topOwnerships = nftData.top_ownerships;
        let tmpOwnerList = [];
        for (let i = 0; i < topOwnerships.length; i++) {
          tmpOwnerList.push(hash(topOwnerships[i].owner.address));
        }
        console.log(tmpOwnerList);

        // to update in a useState;
        for (let i = 0; i < tmpOwnerList.length; i++) {
          setHashedOwnerList( previousList => {
            return [
              ...previousList,
              tmpOwnerList[i]
            ]
          });
        }
      }
    }
  }, [qrData, nftData, hashedOwnerList]);

使用的函式 buf2hex() 在昨日已提過了,可見昨日文章,而 hash() 則是將 message 與地址進行 encodePacked() 再執行 keccak256() 並轉成 hex 的形式。

const hash = (addr) => {
    const addedMessage = "token3_audience_tickets";
    const encodePackedMessage = Web3.utils.encodePacked( addedMessage, addr);
    const hashedMessage = buf2hex(keccak256(encodePackedMessage));
    return hashedMessage;
}

最後設置當 scanner 掃瞄到資料便開始比對資料是否有對應者,有的話就 alert('Verify Success! You can get in'),沒有的話則判斷其持有假的 NFT QRCode。

Presentation

Closing

將 QRCode 轉換成資料真的花費了我好多時間,中間還一度要改用其他套件,但用來用去似乎還是這個最簡單明瞭。另外也搞懂了一些關於 event 的知識,希望未來在處理 event 時可以更順手!

Ref:


若有文章內有任何錯誤的地方歡迎指點與討論!非常感謝!

歡迎贊助窮困潦倒大學生
0xd8538ea74825080c0c80B9B175f57e91Ff885Cb4


上一篇
【DAY25】- Verification System (abi.encodePacked 解析)
下一篇
【DAY27】Verification System (Smart Contract I)
系列文
Road Map To DApp Developer30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言